﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading;
using GosafeTest;
using System.Data;
//using SIGGREProto.Util;

namespace TCPServer
{
    class LogDatabase
    {
        private Thread logThread;
        private byte[] messageReceived = null;
        //private byte[] messageReceived = new byte[4096];

        WindowsFormsApplication1.GenericDatabase logDB = null;

        //private SynchronizationContext byte[] messageReceived;

        System.Data.OleDb.OleDbDataAdapter logDA = null;
        System.Data.OleDb.OleDbDataAdapter currentDataAdapter = null;

        System.Data.DataSet logDataSet = null;

        System.Data.DataTable dtLog = null;
        System.Data.DataTable dtDevice = null;

        string IPinternet = IPMonitor.GetExternalIP();
        string IPDevice = "";

        string lastValidLongitude = "";
        string lastValidLatitude = "";

        public string IPDeviceEmbedded
        {
            get { return IPDevice; }
            set { IPDevice = value; }
        }

        public LogDatabase(string IPDevice):this()
        {
            this.IPDevice = IPDevice;
        }

        public LogDatabase()
        {
            ////Provider=SQLOLEDB.1;Password=gfaf61;Persist Security Info=True;User ID=sa;Initial Catalog=MERCATOR;Data Source=www.lifeware.com.br\sqlexpress,2447
            ////string connString="Provider=SQLOLEDB.1;Password=gfaf61;Persist Security Info=True;User ID=sa;Initial Catalog=MERCATOR;Data Source=www.lifeware.com.br\\sqlexpress,2447";
            ////string connString = "Provider=SQLOLEDB.1;Password=life2011;Persist Security Info=True;User ID=sa;Initial Catalog=MERCATOR_hist;Data Source=www.lifeware.com.br\\sqlexpress,2272";
            //string connString = "Provider=SQLOLEDB.1;Password=life2011;Persist Security Info=True;User ID=sa;Initial Catalog=MERCATOR_hist;Data Source=192.168.1.101\\sqlexpress,2272";

            ////dataToExportConnString = config.getDataToExportConnString();

            //logDB = new WindowsFormsApplication1.GenericDatabase();
            //logDB.Open(connString);

            ////System.Data.DataTable dt = logDB.GetTableDataByName("RelayLog");
            //getLogData("RelayLog");
            ////System.Data.DataTable dt = tableDataSet.Tables[0];
            //dtLog = logDataSet.Tables[0];

            this.logThread = new Thread(new ThreadStart(WriteLoop));
            this.logThread.Start();
        }

        public LogDatabase(string IPinternet, string IPDevice):this()
        {
            this.IPinternet = IPinternet;
            this.IPDevice = IPDevice;
        }

        public void WriteLoop()
        {
            //this.tcpListener.Start();

            // gravar no banco MERCATOR_test
            // Tabela RelayLog
            //ID	int	Unchecked
            //ReceivedDateTime	datetime	Unchecked
            //ReceivedBytes	char(4096)	Unchecked
            //ReceivedASCII	text	Unchecked

            while (true)
            {
                ////blocks until a client has connected to the server
                //TcpClient client = this.tcpListener.AcceptTcpClient();

                //Console.WriteLine(DateTime.Now + " Accepted connection from " + client.Client.RemoteEndPoint.ToString());

                //Console.WriteLine(DateTime.Now + " Trying to connect on Gosafe Server ");
                //IPEndPoint serverEndPoint = new IPEndPoint(Dns.GetHostEntry("www.anytracking.cn").AddressList[0], 3030);//80);// 3030);
                //clientGosafeServer = new TcpClient();
                //receiveCallbackDelegate = new AsyncCallback(ReceiveCallback);
                //clientGosafeServer.Connect(serverEndPoint);

                ////create a thread to handle communication
                ////with connected client
                //Thread clientThread = new Thread(new ParameterizedThreadStart(HandleClientComm));
                //clientThread.Start(client);

                if (this.messageReceived != null)
                {
                    Console.WriteLine("Message received: ");

                    this.messageReceived = null;
                }

                Thread.Sleep(1000);
            }
        }

        internal void setDataAvaiable(byte[] packet, bool saveLog)
        {
            SIGGREProto.GosafeParser.parsePacket(packet, false, this.IPDevice);

            // metodo antigo
            //parseMessage(messageItem, true);
        }

        internal void parseMessage(byte[] message, bool saveLog)
        {
            try
            {
                byte[] messageReceived = new byte[message.Length];
                message.CopyTo(messageReceived, 0);

                //messageReceived = new byte[message.Length];
                //message.CopyTo(this.messageReceived, 0);

                //char[] cArray = System.Text.Encoding.ASCII.GetString(messageReceived).ToCharArray();

                string bytesString = System.Text.Encoding.ASCII.GetString(messageReceived);
                string bytesASCII = BitConverter.ToString(messageReceived, 0, messageReceived.Length);
                Console.WriteLine(DateTime.Now + " Bytes Received: " + bytesASCII);

                string longitude = ""; string latitude = ""; 
                string latitudeDec =""; string longitudeDec = "";

                string bytesASCIIstr = bytesASCII.Replace("-", ""); // remove separadores dos bytes ASCII

                string messageType = bytesASCIIstr.Substring(0, 2);

                string obs = "";
                string deviceID = ""; // Numero de série de identificação do dispositivo embarcado    
                string deviceTime = "";
                string deviceDate = "";

                // Verifica se o tipo de mensagem é de latitude e longitude
                if (message[0] == 36)
                {
                    try
                    {                        
                        deviceID = bytesASCIIstr.Substring(2, 10);
                        Console.WriteLine(DateTime.Now + "DeviceID: " + deviceID);

                        deviceTime = bytesASCIIstr.Substring(12, 6);
                        Console.WriteLine(DateTime.Now + "deviceTime: " + deviceTime);

                        deviceDate = bytesASCIIstr.Substring(18, 6);
                        Console.WriteLine(DateTime.Now + "deviceDate: " + deviceDate);

                        obs = "DeviceID: " + deviceID + " - deviceTime: " + deviceTime + " - deviceDate: " + deviceDate;
                        
                        //24-96-61-11-23-09-13-09-51-10-09-11-  20-21-30-22-00-     04-01-73-03-02-00-00-00-FF-FF-FB-FF-FF-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-04
                        //                              12+4    2021.3083  S   17+4 04017.3066 W     
                        latitude = BitConverter.ToString(message, 12, 2).Replace("-", "") + "." + BitConverter.ToString(message, 14, 2).Replace("-", "") + "'";
                        longitude = BitConverter.ToString(message, 17, 2).Replace("-", "") + BitConverter.ToString(message, 19, 3).Replace("-", "") + "'";
                        //longitude = longitude.Substring(0, 5) + "." + longitude.Substring(5, 2);
                        //longitude = longitude.Substring(0, 5)  + longitude.Substring(5, 2);
                        longitude = longitude.Substring(0, 5) + longitude.Substring(5, 4);
                        Console.WriteLine(DateTime.Now + " Latitude + Longitude: " + latitude + " - " + longitude);

                        string latitudeDegreeStr = BitConverter.ToString(message, 12, 1).Replace("-", "");
                        //string latitudeMinuteStr = BitConverter.ToString(message, 13, 1).Replace("-", "") + "." + BitConverter.ToString(message, 14, 2).Replace("-", "");
                        string latitudeMinuteStr = BitConverter.ToString(message, 13, 1).Replace("-", "") +  BitConverter.ToString(message, 14, 2).Replace("-", "");

                        string longitudeDegreeStr = longitude.Substring(0, 3).Replace("-", "");
                        //string longitudeMinuteStr = longitude.Substring(3, 2).Replace("-", "") + "." + BitConverter.ToString(message, 5, 2).Replace("-", "");
                        //string longitudeMinuteStr = longitude.Substring(3, 2).Replace("-", "") + BitConverter.ToString(message, 5, 2).Replace("-", "");
                        string longitudeMinuteStr = longitude.Substring(3, 6).Replace("-", "");
                        //longitudeMinuteStr = longitudeMinuteStr.Substring(3, 8);

                        //latitudeMinuteStr += "." + BitConverter.ToString(message, 14, 2).Replace("-", "");
                        //longitudeMinuteStr += "." + BitConverter.ToString(message, 5, 2).Replace("-", "");

                        Console.WriteLine(DateTime.Now + " Latitude: " + latitudeDegreeStr + "º " + latitudeMinuteStr + "'");
                        Console.WriteLine(DateTime.Now + " Longitude: " + longitudeDegreeStr + "º " + longitudeMinuteStr + "'");

                        longitude = longitudeDegreeStr + "º " + longitudeMinuteStr + "'";
                        latitude = latitudeDegreeStr + "º " + latitudeMinuteStr + "'";

                        latitudeDec = latitude;
                        longitudeDec = longitude;

                        Console.WriteLine(DateTime.Now + " Longitude: " + ConvertDegreeAngleToDouble(double.Parse(longitudeDegreeStr), double.Parse(longitudeMinuteStr)/10000, 0));
                        Console.WriteLine(DateTime.Now + " latitude: " + ConvertDegreeAngleToDouble(double.Parse(latitudeDegreeStr), double.Parse(latitudeMinuteStr)/10000, 0));

                        longitude = "-" + ConvertDegreeAngleToDouble(double.Parse(longitudeDegreeStr), double.Parse(longitudeMinuteStr)/10000, 0).ToString();
                        latitude = "-" + ConvertDegreeAngleToDouble(double.Parse(latitudeDegreeStr), double.Parse(latitudeMinuteStr)/10000, 0).ToString();

                        lastValidLatitude = latitude;
                        lastValidLongitude = longitude;
                    }
                    catch (Exception ex)
                    {
                        Console.WriteLine(DateTime.Now + " - Erro : " + ex.Message + "\nStackTrace: " + ex.StackTrace );
                        //throw;
                    }
                }

                if ((latitude == null) || (latitude.Trim().Length == 0) )
                    latitude = lastValidLatitude;

                if ((longitude == null) || (longitude.Trim().Length == 0))
                    longitude = lastValidLongitude;

                if (saveLog)
                {
                    dtLog.Rows.Add(null, DateTime.Now, bytesString, bytesASCII, IPinternet, IPDevice, latitude, longitude, latitudeDec,
                        longitudeDec, obs, deviceID, deviceTime, deviceDate);
                    saveLogTable(logDA);
                }

                Console.WriteLine("DeviceID: " + deviceID + " - deviceTime: " + deviceTime + " - deviceDate: " + deviceDate);

                if((deviceID!=null) && (deviceID.Trim()!=""))
                {
                    int bytesQty = message.Length;

                    if(saveLog)
                        SaveDeviceTable(DateTime.Now, bytesString, bytesASCII, IPinternet, IPDevice, latitude, longitude, latitudeDec,
                            longitudeDec, obs, deviceID, deviceTime, deviceDate, bytesQty);

                    Console.WriteLine(DateTime.Now + " - Device atualizado");
                }
                
                // Verifica se o tipo de mensagem é de *HQ *= 42 dec ou 2A hexa
                if (message[0] == 42)
                {
                    string emailBody = "Prezado usuário, \n\tEste é um aviso automático do Servidor Mercator 2.0. \n\n\tPor favor, não responda a este e-mail.";
                    emailBody += "\n\n\tEndereço IP do servidor Mercator ativo: " + IPinternet;
                    emailBody += "\n\n\tMensagem recebida do dispositivo embarcado de número <" + deviceID +
                        "> acabou de RE-CONECTAR no servidor Mercator da Lifeware";
                    emailBody += "\n\n\t A mensagem de pedido de reconexão foi: " + bytesString;
                    emailBody += "\n\n\t Os últimos dados válidos recebidos desse dispsoitivo foram: ";
                    emailBody += "\n\n\tData Hora: " + DateTime.Now;
                    emailBody += "\n\n\tLatitude e Longitude: " + lastValidLatitude + "/" + lastValidLongitude;
                    emailBody+="\n\n\tEndereço: " + "<funcionalidade em desenvolvimento>";

                    //GosafeRelayTest.UtilMail.SendGmail("gerson.freire@gmail.com", "gersonfaf61", "gerson.freire@gmail.com",
                    //    "mercator2web@gmail.com", "mercator2web@gmail.com", "Lifeware Mercator 2.0 - Notificação automática", emailBody, false);

                    Console.WriteLine(DateTime.Now + " RE-Connection notification e-mail sent ...");
                }

                //ID	int	Unchecked
                //ReceivedDateTime	datetime	Unchecked
                //ReceivedBytes	varchar(4096)	Unchecked
                //ReceivedASCII	text	Unchecked
                //ServerIP	varchar(50)	Unchecked
                //DeviceIP	varchar(50)	Checked
                //Latitude	varchar(50)	Checked
                //Longitude	varchar(50)	Checked
                //LatitudeDecimal	varchar(50)	Checked
                //LongitudeDecimal	varchar(50)	Checked
                //Obs	text	Checked
                //DeviceID	varchar(50)	Checked
                //DeviceTime	varchar(50)	Checked
                //DeviceDate	varchar(50)	Checked
            }
            catch (Exception ex)
            {
                Console.WriteLine(DateTime.Now + " - Erro : " + ex.Message + "\nStackTrace:" + ex.StackTrace);
                //throw;
            }
        }

        private void SaveDeviceTable(DateTime dateTime, string bytesString, string bytesASCII, 
            string IPinternet, string IPDevice, string latitude, string longitude, string latitudeDec, 
            string longitudeDec, string obs, string deviceID, string deviceTime, string deviceDate,
            int bytesQty)
        {
            try
            {
                DataTable dtDevice = null; 

                // Insere ou atualiza dados na tabela de dispositivos

                // Primeiro, verifica se dispositivo já está cadastrado
                DataSet deviceDS = getData("Device"," DeviceID='" + deviceID + "'");
                dtDevice = deviceDS.Tables[0];

                // Se dispositivo já existe no cadastro
                if ((deviceDS.Tables.Count > 0) && (deviceDS.Tables[0].Rows.Count > 0))
                {
                    dtDevice.Rows[0]["ServerIP"] = IPinternet;
                    dtDevice.Rows[0]["DeviceIP"] = IPDevice;
                    dtDevice.Rows[0]["LastUploadDate"] = DateTime.Today.ToString();
                    dtDevice.Rows[0]["LastUploadTime"] = DateTime.Now.ToString();

                    int bytesQtyOld = 0;
                    if(int.TryParse(dtDevice.Rows[0]["TotalBytesReceivedDay"].ToString(), out bytesQtyOld))
                        bytesQtyOld += bytesQty;
                    dtDevice.Rows[0]["TotalBytesReceivedDay"] = bytesQtyOld;
                    if (int.TryParse(dtDevice.Rows[0]["TotalBytesReceivedMonth"].ToString(), out bytesQtyOld))
                        bytesQtyOld += bytesQty;
                    dtDevice.Rows[0]["TotalBytesReceivedMonth"] = bytesQtyOld;

                    try
                    {
                        if (double.Parse(longitude.Replace(",", ".")) != 0)
                            dtDevice.Rows[0]["LastLongitude"] = longitude;
                        if (double.Parse(latitude.Replace(",", ".")) != 0)
                            dtDevice.Rows[0]["LastLatitude"] = latitude;
                    }
                    catch (Exception ex)
                    {
                        Console.WriteLine(DateTime.Now + " - Erro : " + ex.Message + "\nStackTrace:" + ex.StackTrace);
                        //throw;
                    }
                }
                // Caso contrário insere novo dispositivo com dados atualizados
                else
                {
                    //DataRowCollection rowCollection = dtDevice.Rows;
                    //// Instantiate a new row using the NewRow method.

                    //DataRow newRow = dtDevice.NewRow();
                    //// Insert code to fill the row with values.

                    //// Add the row to the DataRowCollection.
                    //dtDevice.Rows.Add(newRow);

                    //DeviceID	varchar(50)	Unchecked
                    //VRN	varchar(50)	Checked
                    //VIN	varchar(50)	Checked
                    //ServerIP	varchar(50)	Checked
                    //DeviceIP	varchar(50)	Checked
                    //SMSManagementNumber	varchar(50)	Checked
                    //LastLongitude	varchar(50)	Checked
                    //LastLatitude	varchar(50)	Checked
                    //LastSpeed	varchar(50)	Checked
                    //LastMileage	varchar(50)	Checked
                    //LastUploadDate	varchar(50)	Checked
                    //LastUploadTime	varchar(50)	Checked
                    //ServerPort	varchar(50)	Checked
                    //GroupID	varchar(50)	Checked
                    //TotalBytesReceivedDay	int	Checked
                    //TotalBytesReceivedMonth	int	Checked
                    //        Unchecked
                    
                    dtDevice.Rows.Add(deviceID, "", "", IPinternet, IPDevice, "", longitude, latitude, 
                       "", "", DateTime.Today.ToString(), DateTime.Now.ToString(), "3030","1", 0, 0);
                }

                // Salva alterações na tabela física subjacente
                object cmdBuilder = null;

                if (currentDataAdapter.GetType() == (new System.Data.OleDb.OleDbDataAdapter()).GetType())
                {
                    cmdBuilder = new System.Data.OleDb.OleDbCommandBuilder((System.Data.OleDb.OleDbDataAdapter)currentDataAdapter);
                    ((System.Data.OleDb.OleDbCommandBuilder)cmdBuilder).GetUpdateCommand();
                    currentDataAdapter.Update(deviceDS);
                }
            }
            catch (Exception ex)
            {
                Console.WriteLine(DateTime.Now + " - Erro : " + ex.Message + "\nStackTrace:" + ex.StackTrace);
                //throw;
            }

            // então atualiza dados do sipositivo
            //DeviceID	varchar(50)	Unchecked
            //VRN	varchar(50)	Checked
            //VIN	varchar(50)	Checked
            //ServerIP	varchar(50)	Checked
            //DeviceIP	varchar(50)	Checked
            //SMSManagementNumber	varchar(50)	Checked
            //LastLongitude	varchar(50)	Checked
            //LastLatitude	varchar(50)	Checked
            //LastSpeed	varchar(50)	Checked
            //LastMileage	varchar(50)	Checked
            //LastUploadDate	varchar(50)	Checked
            //LastUploadTime	varchar(50)	Checked
        }

        public void saveLogTable(System.Data.OleDb.OleDbDataAdapter  currentDBAdapter)
        {
            object cmdBuilder = null;

            if (logDA.GetType() == (new System.Data.OleDb.OleDbDataAdapter()).GetType())
            {
                cmdBuilder = new System.Data.OleDb.OleDbCommandBuilder((System.Data.OleDb.OleDbDataAdapter)logDA);
                ((System.Data.OleDb.OleDbCommandBuilder)cmdBuilder).GetUpdateCommand();
                logDA.Update(logDataSet);
            }
        }

        public System.Data.DataSet getData(string currentTableName, string whereClause)
        {
            System.Data.DataSet tempDataSet = new System.Data.DataSet();

            try
            {
                string SQL = "SELECT * FROM " + currentTableName;
                if ((whereClause != null) && (whereClause.Trim() != ""))
                    SQL += " WHERE " + whereClause;

                System.Data.OleDb.OleDbCommand tableCommand =
                      new System.Data.OleDb.OleDbCommand(SQL,
                          ((System.Data.OleDb.OleDbConnection)logDB.Connection));

                currentDataAdapter = new System.Data.OleDb.OleDbDataAdapter(tableCommand);

                currentDataAdapter.Fill(tempDataSet);
            }
            catch (Exception ex)
            {
                Console.WriteLine(DateTime.Now + " - Erro : " + ex.Message + "\nStackTrace:" + ex.StackTrace);
                //throw;
            }

            return tempDataSet;
        }

        public void getLogData(string currentTableName)
        {

            try
            {
                System.Data.OleDb.OleDbCommand tableCommand =
              new System.Data.OleDb.OleDbCommand("SELECT * FROM " + currentTableName,
                  ((System.Data.OleDb.OleDbConnection)logDB.Connection));

                logDataSet = new System.Data.DataSet();

                logDA = new System.Data.OleDb.OleDbDataAdapter(tableCommand);

                logDA.Fill(logDataSet);
            }
            catch (Exception ex)
            {

                throw;
            }
        }

        public double ConvertDegreeAngleToDouble(double degrees, double minutes, double seconds)
        {
            //Decimal degrees = 
            //   whole number of degrees, 
            //   plus minutes divided by 60, 
            //   plus seconds divided by 3600

            return degrees + (minutes / 60) + (seconds / 3600);
        }

        static void Main(string[] args)
        {
            //testDataAvaible();
            testMessageParser();
        }

        //Ver mapa	-20,3551616666667	-40,2878816666667		
        // 2A-48-51-2C-39-36-36-31-31-31-32-33-30-39-2C-41-2C-30-32-32-32-35-30-2C-31-32-31-30-31-31-23-
        // 24-96-61-11-23-09-02-19-52-12-10-11-20-21-29-36-00-04-01-73-01-02-00-00-00-FF-FF-FB-FF-FF-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-12	
        // 177.19.217.126	11/10/2011 23:23:00	*HQ,9661112309,A,022250,121011#$?a# R !)6s?????     
        public static void testDataAvaible()
        {
            string dataReceived = "2A-48-51-2C-39-36-36-31-31-31-32-33-30-39-2C-41-2C-30-32-32-32-35-30-2C-31-32-31-30-31-31-23-";
            // 31 = 24/36 32 = 96/150 
            dataReceived += "24-96-61-11-23-09-02-19-52-12-10-11-20-21-29-36-00-04-01-73-01-02-00-00-00-FF-FF-FB-FF-FF-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-12";

            byte[] hexByteString = StringToByteArray(dataReceived.Replace("-",""));
            //byte[] hexByteString2 = strToByteArray(dataReceived.Replace("-", ""));

            //LogDatabase logDatabase= new LogDatabase();
            //logDatabase.setDataAvaiable(hexByteString);

            string hexASCII = ByteArrayToString(hexByteString);

            string bytesString = System.Text.Encoding.ASCII.GetString(hexByteString);

            string[] messagesArray = bytesString.Split(new Char[] { '\x24' });

            //int positionNewMessage = hexByteString.First(number => number == 36);
            int positionNewMessage = Array.IndexOf(hexByteString, '\x24');

            string[] dinosaurs =
              {
                  "Compsognathus", "Amargasaurus", "Oviraptor",
                  "Velociraptor",  "Deinonychus",  "Dilophosaurus",
                  "Gallimimus",    "Triceratops"
              };
            Predicate<string> dinoType;
            dinoType = EndsWithSaurus;
            string[] subArray =
                Array.FindAll(dinosaurs, dinoType);


            foreach (string messageItem in messagesArray)
            {
                byte[] b2 = System.Text.Encoding.ASCII.GetBytes(messageItem);
                b2 = System.Text.Encoding.UTF8.GetBytes(messageItem);

                System.Text.ASCIIEncoding enc = new System.Text.ASCIIEncoding();
                b2 = enc.GetBytes(messageItem);

                //byte[] hexByteString2 = StringToByteArray(messageItem);
                LogDatabase logDatabase2 = new LogDatabase();
                byte[] b3;//=new byte[b2.Length + 1];

                if (b2[0] == 42)
                {
                    b3 = new byte[b2.Length];
                    b2.CopyTo(b3, 0);
                }
                else
                {
                    b3 = new byte[b2.Length + 1];
                    b3[0] = 36;
                    b2.CopyTo(b3, 1);
                }

                logDatabase2.messageReceived = new byte[b2.Length];
                logDatabase2.setDataAvaiable(b3, false);
            }

            //char[] message=dataReceived.ToCharArray();

            //BitConverter.GetBytes();
        }      // Search predicate returns true if a string ends in "saurus".

        // parser baseado em máquina de estado que analisa byte a byte
        public static void testMessageParserByte()
        {
            string dataReceived = "2A-48-51-2C-39-36-36-31-31-31-32-33-30-39-2C-41-2C-30-32-32-32-35-30-2C-31-32-31-30-31-31-23-";
            // posicao 31 = 24dec/36hex  posicao 32 = 96hex/150dec
            dataReceived += "24-96-61-11-23-09-02-19-52-12-10-11-20-21-29-36-00-04-01-73-01-02-00-00-00-FF-FF-FB-FF-FF-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-12";

            byte[] hexByteString = StringToByteArray(dataReceived.Replace("-", ""));

            byte[][] HQmessagesBytes;
            byte[][] binaryMessagesBytes;

            // flags de inicio e fim de mensagem binaria
            bool startBinaryMessage = false;
            bool endBinaryMesssage = false;

            // flags de inicio e fim de mensagem *HQ
            bool startHQmessage = false;
            bool endHQmessage = false;

            // flag d inicio de mensagem desconhecida
            bool startUnknownMessage = false;

            // contador de bytes da mensagem
            int messageByteCounter = -1;

            // máquina de estado para separar o pacote de bytes recebidos em mensagens
            foreach (byte byteItem in hexByteString)
            {
                byte[] messageItem;
                messageByteCounter++;

                // verifica e trata cada um dos estados atuais da maquina de estado:

                // se estiver lendo mensagem do tipo binaria que comeca com hexa 24 ou decimal 36
                if (startBinaryMessage)
                {

                }

                // se estiver lendo mensagem do tipo *HQ
                else if (startHQmessage)
                {

                }

                // se estiver lendo mensagem desconhecida
                else if (startUnknownMessage)
                {

                }

                // caso tenha finalizado uma mensagem do tipo binaria
                else
                {

                }

                // se for mensagem do tipo *HQ
                //if (hexByteString[0] == '*' && hexByteString[1] == 'H' && hexByteString[2] == 'Q')
                if (byteItem == '*' && hexByteString[messageByteCounter + 1] == 'H' && hexByteString[messageByteCounter + 2] == 'Q')
                {
                    // sinaliza flag de inicio de mensagem binaria
                    startBinaryMessage = true;
                }

                // mensagem começa com hexa 24 ou decima 36 então é inicio de mensagem binaria
                else if (byteItem == '\x24')
                {
                    startHQmessage = true;
                }

                // mensagem não reconhecida para protocolo Gosafe
                else
                {
                    startUnknownMessage = true;
                }
            }

        }
        
        // Parser baseado em metodo Split da classe String
        public static void testMessageParser()
        {
            // simulacao de duas mensagens concatenadas a primeira do tipo *HQ e a segunda do tipo binaria, 
            // comecando com hex 24 dec 36

            // monta strings com valores hexadecimais dos bytes do pacote de mensagens concatenadas
            string dataReceived = "2A-48-51-2C-39-36-36-31-31-31-32-33-30-39-2C-41-2C-30-32-32-32-35-30-2C-31-32-31-30-31-31-23-";
            // posicao 31 = 24dec/36hex  posicao 32 = 96hex/150dec
            dataReceived += "24-96-61-11-23-09-02-19-52-12-10-11-20-21-29-36-00-04-01-73-01-02-00-00-00-FF-FF-FB-FF-FF-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-12";

            // converte string hexa simulada vetor de bytes de mensagens concatenadas
            byte[] hexByteString = StringToByteArray(dataReceived.Replace("-", ""));
            
            // teste de reversão de bytes - desconsiderar esta linha por enquanto
            string bytesString = System.Text.Encoding.ASCII.GetString(hexByteString);

            // separa mensagens no pactoe paseado no caracter de inicio de mensagem binaria, caracter $ decimal 36 hexa 24
            string[] messagesArray = bytesString.Split(new Char[] { '\x24' });

            // vetor de tamanhos de mensagens
            int[] messagesLen = new int[messagesArray.Length];

            // vetor de bytes de mensagens obtidas da quebra do pacote
            byte[][] messagesBytes = new byte[messagesArray.Length][];

            // contador de mensagens lidas dentro do pacote de bytes
            int messagesLenCounter = 0;

            // ponteiro para posição de inicio da mensagem atual dentro do vetor de bytes do pacote inteiro
            int cursorMessageStartPosition = 0;

            // primeiro percorre vetor de mensagens separadas por Split 
            // para ober o tamanho de cada mensagem num array de tamanhos
            foreach (string messageItem in messagesArray)
            {
                // teste de reversão de bytes - desconsiderar esta linha por enquanto
                byte[] test = (new System.Text.ASCIIEncoding()).GetBytes(messageItem);

                // param mensagens que não sejam binarias, ou seja,
                // que sejam tipo *HQ, o tamanho já inclui o byte inicial 
                if (messageItem.ToCharArray()[0] == '*')
                    messagesLen[messagesLenCounter] = messageItem.Length;

                // caso seja uma mensagem do tipo binaria, soma mais um para consigerar o caracter hexa 24 que foi retirado no metodo Split
                // e reinsere o caracter de inicio de mensagem na primeira posição da mensagem
                else
                {
                    messagesLen[messagesLenCounter] = messageItem.Length + 1;
                }

                // reserva bytes na memoria para mensagem
                Array.Resize(ref messagesBytes[messagesLenCounter], messagesLen[messagesLenCounter]);

                // copia trecho do pacote que contem a mensagem para o vetor de bytes de mensagens separadas
                Array.Copy(hexByteString,cursorMessageStartPosition,messagesBytes[messagesLenCounter],0,messagesLen[messagesLenCounter]);

                // resposiciona ponteiro para posição de inicio da mensagem atual dentro do vetor de bytes do pacote inteiro
                cursorMessageStartPosition += messagesLen[messagesLenCounter++];
                
            }

        }

        private static bool EndsWithSaurus(string s)
        {
            if ((s.Length > 5) &&
                (s.Substring(s.Length - 6).ToLower() == "saurus"))
            {
                return true;
            }
            else
            {
                return false;
            }
        }

        //http://stackoverflow.com/questions/311165/how-do-you-convert-byte-array-to-hexadecimal-string-and-vice-versa-in-c
        public static byte[] StringToByteArray(String hex)
        {
            int NumberChars = hex.Length;
            byte[] bytes = new byte[NumberChars / 2];
            for (int i = 0; i < NumberChars; i += 2)
                bytes[i / 2] = Convert.ToByte(hex.Substring(i, 2), 16);
            return bytes;
        }

        public static string ByteArrayToString(byte[] byteArrayToConvert)
        {
            string hex = BitConverter.ToString(byteArrayToConvert);
            return hex;// hex.Replace("-", "");
        }

        //http://stackoverflow.com/questions/311165/how-do-you-convert-byte-array-to-hexadecimal-string-and-vice-versa-in-c
        public static string ByteArrayToString2(byte[] ba)
        {
            StringBuilder hex = new StringBuilder(ba.Length * 2);
            foreach (byte b in ba)
                hex.AppendFormat("{0:x2}", b);
            return hex.ToString();
        }

        public static byte[] strToByteArray(string str)
        {
            System.Text.ASCIIEncoding enc = new System.Text.ASCIIEncoding();
            return enc.GetBytes(str);
        }

    }
}

#region code backup


//char MyChar = 'X';        // Character literal
//char MyChar1 = '\x0058';   // Hexadecimal
//char MyChar2 = (char)24;   // Cast from integral type
//char MyChar3 = '\u0058';   // Unicode

#endregion

// Convert Byte array to Base64 Char Array
//using System;
//using System.IO;

//class Test {
//    public static void Main() {
//        // The size of the char[] must 
//        // be at least 4/3 the size of the source byte[] and must be 
//        // divisible by 4.
//        byte[] data = { 0x01, 0x02, 0x5A, 0xFF, 0x0, 0xF0, 0x4D, 0x62, 0x78,  
//            0xD2, 0xC5, 0xA1, 0x5A, 0xD6, 0x0C, 0xA9, 0xA6, 0x63, 0x3D, 0xC2, 
//            0xD5, 0x0F, 0xCC, 0x01, 0xF2, 0x0C};

//        char[] base64data =  new char[(int)(Math.Ceiling((double)data.Length / 3) * 4)];

//        Console.WriteLine("\nByte array encoding/decoding");
//        Convert.ToBase64CharArray(data, 0, data.Length, base64data, 0);
//        Console.WriteLine(new String(base64data));
//    }
//}

//ID	int	Unchecked
//ReceivedDateTime	datetime	Unchecked
//ReceivedBytes	char(4096)	Unchecked
//ReceivedASCII	text	Unchecked

//byte[] a = new byte[50];
//char [] cArray= System.Text.Encoding.ASCII.GetString(a).ToCharArray();